package cloudspace.vm.javassist;

import java.util.List;

import javassist.CannotCompileException;
import javassist.CtClass;


/**
 * The Class AbstractCommand. This class represents the most basic functions of
 * a command as interpreted by a javassist configuration file.
 */
public abstract class AbstractCommand implements CommandInterface
{
    /**
     * The Class CommandNotImplementedException. This exception results from a
     * command that requires operations not implemented by javassist.
     */
    public class CommandNotImplementedException
                    extends
                    MalformedCommandException
    {

        /** The Constant serialVersionUID. */
        private static final long serialVersionUID = 1L;


        /**
         * Instantiates a new command not implemented exception.
         * 
         * @param command
         *            the command
         */
        public CommandNotImplementedException( CommandInterface command )
        {
            super( "The combination of Translation Type and Signature Type is not supported:  "
                + command.toString() );
        }

    }


    /**
     * The Class MalformedCommandArgumentException. This exception results from
     * a command argument that is not properly formated in a javassist config
     * file.
     */
    public class MalformedCommandArgumentException
                    extends
                    MalformedCommandException
    {

        /** The Constant serialVersionUID. */
        private static final long serialVersionUID = 1L;


        /**
         * Instantiates a new malformed command argument exception.
         * 
         * @param argList
         *            the arg list
         */
        public MalformedCommandArgumentException( List<String> argList )
        {
            super( "The arguments parsed are not in the correct format:  "
                + argList.toString() );
        }

    }


    /**
     * The Enum SignatureType. The type of signature to translate.
     */
    public enum SignatureType {
        CONSTRUCTORCALL,
        NEWEXPR,
        METHODCALL,
        STATICDEFINITION,
        NEWARRAY,
        FIELDACCESS,
        INSTANCEOF,
        CAST,
        HANDLER,
        METHODBODY
    };

    /** The sig type. */
    SignatureType sigType;

    /** The un parsed args. */
    List<String> unParsedArgs;

    /** The trans type. */
    // TranslationType transType;

    /** The command. */
    String command;

    /** The signature. */
    String signature;


    /**
     * Instantiates a new abstract command using a list of arguments parsed from
     * a configuration file.
     * 
     * @param argList
     *            the arguments parsed from a javassist config file
     * 
     * @throws MalformedCommandException
     *             the malformed command exception
     */
    protected AbstractCommand( List<String> argList )
        throws MalformedCommandException
    {
        unParsedArgs = argList;
        sigType = findSignatureType();
        // transType = findTranslationType();
        signature = findSignature();
        command = findReplacement();

    }


    /*
     * (non-Javadoc)
     * 
     * @see cloudspace.vm.javassist.commands.CommandInterface#getSignatureType
     * ()
     */
    public SignatureType getSignatureType()
    {
        return sigType;
    }


    public String getReplacement()
    {
        return command;
    }


    /*
     * (non-Javadoc)
     * 
     * @see cloudspace.vm.javassist.commands.CommandInterface#getSignature ()
     */
    public String getSignature()
    {
        return signature;
    }


    public String getShortSignature()
    {
        int firstParen = signature.indexOf( '(' );
        int lastPackageSep = signature.substring( 0, firstParen )
            .lastIndexOf( '.' );

        return signature.substring( lastPackageSep + 1 );
    }


    // List<String> unParsedArgs;
    /*
     * (non-Javadoc)
     * 
     * @see java.lang.Object#toString()
     */
    public String toString()
    {
        return unParsedArgs.toString();
    }


    /**
     * a utility method for finding replacement text
     * 
     * @return the replacement text
     * 
     * @throws MalformedCommandArgumentException
     *             the malformed command argument exception
     */
    private String findReplacement() throws MalformedCommandArgumentException
    {

        String rep;
        try
        {
            String replText = unParsedArgs.get( 3 ).trim();
            rep = replText.substring( 1, unParsedArgs.get( 3 ).length() - 1 );
        }
        catch ( IndexOutOfBoundsException ex )
        {
            throw new MalformedCommandArgumentException( unParsedArgs );
        }
        // rep =
        rep = rep.trim();
        return rep;
    }


    /*
     * public String getDynamicReplacement() { //return
     * "if($0 != null && !cloudspace.vm.javassist.ClassAnalyzer.rewriteNeeded($0.getClass(),\""
     * + getShortSignature() + "\")){ $_=$proceed($$);}else{" +
     * getReplacement()+ "}"; return command; }
     */

    /**
     * A utility method for finding the signature.
     * 
     * @return the string
     * 
     * @throws MalformedCommandArgumentException
     *             the malformed command argument exception
     */
    private String findSignature() throws MalformedCommandArgumentException
    {

        String sig;
        try
        {
            sig = unParsedArgs.get( 2 );
        }
        catch ( IndexOutOfBoundsException ex )
        {
            throw new MalformedCommandArgumentException( unParsedArgs );
        }
        return sig;
    }


    /**
     * a utility method for finding the type of signature.
     * 
     * @return the signature type
     * 
     * @throws MalformedCommandArgumentException
     *             the malformed command argument exception
     * @throws MalformedSignatureTypeException
     *             the malformed signature type exception
     */
    private SignatureType findSignatureType() throws MalformedCommandException
    {
        String commandType;
        try
        {
            commandType = unParsedArgs.get( 1 );
        }
        catch ( IndexOutOfBoundsException ex )
        {
            throw new MalformedCommandArgumentException( unParsedArgs );
        }
        if ( commandType.equals( "ConstructorCall" ) )
        {
            return SignatureType.CONSTRUCTORCALL;
        }
        else if ( commandType.equals( "NewExpr" ) )
        {
            return SignatureType.NEWEXPR;
        }
        else if ( commandType.equals( "MethodCall" ) )
        {
            return SignatureType.METHODCALL;
        }
        else if ( commandType.equals( "StaticDefinition" ) )
        {
            return SignatureType.STATICDEFINITION;
        }
        else if ( commandType.equals( "Handler" ) )
        {
            return SignatureType.HANDLER;
        }
        else if ( commandType.equals( "Cast" ) )
        {
            return SignatureType.CAST;
        }
        else if ( commandType.equals( "InstanceOf" ) )
        {
            return SignatureType.INSTANCEOF;
        }
        else if ( commandType.equals( "FieldAccess" ) )
        {
            return SignatureType.FIELDACCESS;
        }
        else if ( commandType.equals( "NewArray" ) )
        {
            return SignatureType.NEWARRAY;
        }
        else if ( commandType.equals( "MethodBody" ) )
        {
            return SignatureType.METHODBODY;
        }

        throw new MalformedCommandException( "The signature type "
            + commandType + " is unknown in command:  "
            + unParsedArgs.toString() );
    }


    public void translate( CtClass clazz )
        throws MalformedCommandException,
        CannotCompileException
    {
        throw new CommandNotImplementedException( this );
    }

}
